package com.lizhen.core.function.thread;


public class ThreadDemo {
    public ThreadDemo() {

    }

    public static void main(String[] args) {
        RunnableImpl runnableImpl1 = new RunnableImpl("RunnableImpl-1");
        runnableImpl1.start();
        RunnableImpl runnableImpl2 = new RunnableImpl("RunnableImpl-2");
        runnableImpl2.start();
        ThreadExt threadExt1 = new ThreadExt("ThreadExt-1");
        threadExt1.start();
        ThreadExt threadExt2 = new ThreadExt("ThreadExt-2");
        threadExt2.start();
        SynchronizedRunnableImpl synchronizedRunnableImpl1 = new SynchronizedRunnableImpl("ConcorrencyRunnableImpl-1");
        synchronizedRunnableImpl1.start();
        SynchronizedRunnableImpl synchronizedRunnableImpl2 = new SynchronizedRunnableImpl("ConcorrencyRunnableImpl-2");
        synchronizedRunnableImpl2.start();

        try {
            Thread.sleep(1000);
            synchronizedRunnableImpl1.suspend();
            System.out.println("Suspending First Thread");
            Thread.sleep(1000);
            synchronizedRunnableImpl1.resume();
            System.out.println("Resuming First Thread");
            synchronizedRunnableImpl2.suspend();
            System.out.println("Suspending thread Two");
            Thread.sleep(1000);
            synchronizedRunnableImpl2.resume();
            System.out.println("Resuming thread Two");
        } catch (InterruptedException e) {
            System.out.println("Main thread Interrupted");
        }
        try {
            System.out.println("Waiting for threads to finish.");
            synchronizedRunnableImpl1.thread.join();
            synchronizedRunnableImpl2.thread.join();
        } catch (InterruptedException e) {
            System.out.println("Main thread Interrupted");
        }
        System.out.println("Main thread exiting.");
    }

    static class RunnableImpl implements Runnable {
        private Thread thread;
        private String threadName;

        RunnableImpl(String name) {
            threadName = name;

            System.out.println("Creating " + threadName);
        }

        public void run() {
            System.out.println("Running " + threadName);
            try {
                for (int i = 4; i > 0; i--) {
                    System.out.println("Thread: " + threadName + ", " + i);

                    Thread.sleep(1000);
                }
            } catch (InterruptedException e) {
                System.out.println("Thread " + threadName + " interrupted.");
            }
            System.out.println("Thread " + threadName + " exiting.");
        }

        public void start() {
            System.out.println("Starting " + threadName);

            if (thread == null) {
                thread = new Thread(this, threadName);
                thread.start();
            }
        }
    }

    static class ThreadExt extends Thread {
        private Thread thread;
        private String threadName;

        ThreadExt(String name) {
            threadName = name;

            System.out.println("Creating " + threadName);
        }

        public void run() {
            System.out.println("Running " + threadName);
            try {
                for (int i = 4; i > 0; i--) {
                    System.out.println("Thread: " + threadName + ", " + i);

                    Thread.sleep(1000);
                }
            } catch (InterruptedException e) {
                System.out.println("Thread " + threadName + " interrupted.");
            }
            System.out.println("Thread " + threadName + " exiting.");
        }

        public void start() {
            System.out.println("Starting " + threadName);

            if (thread == null) {
                thread = new Thread(this, threadName);
                thread.start();
            }
        }
    }

    static class SynchronizedRunnableImpl implements Runnable {
        public Thread thread;
        boolean suspended = false;
        private String threadName;

        SynchronizedRunnableImpl(String name) {
            threadName = name;

            System.out.println("Creating " + threadName);
        }

        public void run() {
            System.out.println("Running " + threadName);
            try {
                for (int i = 10; i > 0; i--) {
                    System.out.println("Thread: " + threadName + ", " + i);

                    Thread.sleep(1000);
                    synchronized (this) {
                        while (suspended) {
                            wait();
                        }
                    }
                }
            } catch (InterruptedException e) {
                System.out.println("Thread " + threadName + " interrupted.");
            }
            System.out.println("Thread " + threadName + " exiting.");
        }

        public void start() {
            System.out.println("Starting " + threadName);

            if (thread == null) {
                thread = new Thread(this, threadName);
                thread.start();
            }
        }

        void suspend() {
            suspended = true;
        }

        synchronized void resume() {
            suspended = false;
            notify();
        }
    }
}

